package com.panfeng.xcloud.common.core.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * httpclient invoker Utils 工具类
 * @author xiaobo
 * @since 2018-4-12
 */
@SuppressWarnings("deprecation")
@Slf4j
public class HttpclientApiInvoker {

	private static PoolingHttpClientConnectionManager connMgr;
	private static RequestConfig requestConfig;

	public static String sendPostForHttpPool(Map<String, String> param, String apiUrl, String tokenId) throws IOException {
		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
		HttpPost httpPost = new HttpPost(apiUrl);
		CloseableHttpResponse response = null;
		HttpEntity entity;

		try {
			httpPost.setConfig(requestConfig);
			// 设置通用的请求属性
			httpPost.addHeader(HTTP.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			httpPost.addHeader("accept", "*/*");
			httpPost.addHeader("Authorization", "Bearer " + tokenId); //认证token
			httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
			httpPost.setHeader(HTTP.CONN_KEEP_ALIVE, "true");

	        //建立一个NameValuePair数组，用于存储欲传送的参数
	        List<NameValuePair> params = new ArrayList<NameValuePair>();
	        for (Entry<String, String> entry : param.entrySet()) {
	            params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
	        }

	        StringEntity se = new StringEntity( JSONObject.toJSONString(param), "UTF-8");
	        //添加参数
	        httpPost.setEntity(se);

			response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				log.error("[HttpclientApiInvoker] invoke failed, response status: {}",statusCode);
				return null;
			}
			entity = response.getEntity();
			if (entity == null) {
				log.error("[HttpclientApiInvoker] invoke failed, response output is null!");
				return null;
			}
			String result = EntityUtils.toString(entity, "utf-8");
			return result;
		} catch (Exception e) {
			log.error("[HttpclientApiInvoker] invoke throw exception, details:{} ", e);
			e.printStackTrace();
		} finally {
			if (response != null) {
				EntityUtils.consume(response.getEntity());
			}
		}
		return null;
	}

	/**
	 * HTTPGet请求
	 * @param params
	 * @param apiUrl
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String sendGetForHttpPool(Map<String, String> params, String apiUrl, String charset) throws IOException {
		if (apiUrl.endsWith("/")) {
			apiUrl = apiUrl.substring(0, apiUrl.length() - 1);
		}
        StringBuffer buffer = new StringBuffer(apiUrl).append("?");
        for (Iterator<Entry<String, String>> iterator = params.entrySet().iterator(); iterator.hasNext();) {
            Entry<String, String> entry = iterator.next();
            buffer.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), charset)).append("&");
            if (!iterator.hasNext()) {
                buffer.deleteCharAt(buffer.length() - 1);
            }
        }

		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
		HttpGet httpGet = new HttpGet(apiUrl);
		CloseableHttpResponse response = null;
		HttpEntity entity;

		try {
			httpGet.setConfig(requestConfig);
			// 设置通用的请求属性
			httpGet.setHeader("accept", "*/*");
			httpGet.addHeader("Content-Type", "application/json;charset=utf-8");
			httpGet.setURI(URI.create(buffer.toString()));
			response = httpClient.execute(httpGet);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				log.error("[HttpclientApiInvoker] invoke failed, response status: {}",statusCode);
				return null;
			}
			entity = response.getEntity();
			if (entity == null) {
				log.error("[HttpclientApiInvoker] invoke failed, response output is null!");
				return null;
			}
			String result = EntityUtils.toString(entity, "utf-8");
			return result;
		} catch (Exception e) {
			log.error("[HttpclientApiInvoker] invoke throw exception, details: {}", e);
		} finally {
			if (response != null) {
				EntityUtils.consume(response.getEntity());
			}
		}
		return null;
	}

	/**
	 * @param url
	 * @param param
	 * @return
	 */
	public static String postForward(String url, Map<String, String> param) {
		String result = "";
		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
		HttpPost httpPost = new HttpPost(url);
		CloseableHttpResponse response = null;
		HttpEntity entity;
		try {
			httpPost.setConfig(requestConfig);
			httpPost.setHeader(HTTP.CONN_KEEP_ALIVE, "true");
	        //建立一个NameValuePair数组，用于存储欲传送的参数
	        List<NameValuePair> params = new ArrayList<NameValuePair>();
	        for (Entry<String, String> entry : param.entrySet()) {
	            params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
	        }
	        UrlEncodedFormEntity se = new UrlEncodedFormEntity(params, Charset.forName("UTF-8"));
	        //添加参数
	        httpPost.setEntity(se);
			response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				log.error("[HttpclientApiInvoker] invoke failed, response status: {}" ,statusCode);
				return result;
			}
			entity = response.getEntity();
			if (entity == null) {
				log.error("[HttpclientApiInvoker] invoke failed, response output is null!");
				return result;
			}
			result = EntityUtils.toString(entity, "utf-8");
			return result;
		} catch (Exception e) {
			log.error("[HttpclientApiInvoker] invoke throw exception, details: {}", e);
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

	public static String buildMapString(Map<String, String> map) {
		StringBuffer sb = new StringBuffer();
		if (null != map && !map.isEmpty()) {
			for (String key : map.keySet()) {
				sb.append(key + "=");
				if (StringUtils.isEmpty(map.get(key))) {
					sb.append("&");
				} else {
					String value = map.get(key);
					try {
						value = URLEncoder.encode(value, "UTF-8");
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
					sb.append(value + "&");
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 请求get
	 * @param url
	 * @param param
	 * @return
	 */
	public static String reGetForward(String url, Map<String, String> param) {
		String result = "";
		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
		HttpGet httpGet = new HttpGet(url);
		CloseableHttpResponse response = null;
		HttpEntity entity;
		try {
			httpGet.addHeader(HTTP.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			httpGet.setConfig(requestConfig);
			httpGet.setHeader(HTTP.CONN_KEEP_ALIVE, "true");
			String urlString  = "";
			if(null != param && !param.isEmpty()){
				urlString  = "?" + buildMapString(param);
			}
			httpGet.setURI(URI.create(url + urlString));
			log.info("[HttpclientApiInvoker] req get, url: {}",(url + urlString));
			response = httpClient.execute(httpGet);
			int statusCode = response.getStatusLine().getStatusCode();
			log.info("[HttpclientApiInvoker] invoking, response status: {}",statusCode);
			if (statusCode != HttpStatus.SC_OK) {
				log.error("[HttpclientApiInvoker] invoke failed, response status: {}",statusCode);
				return result;
			}
			entity = response.getEntity();
			if (entity == null) {
				log.error("[HttpclientApiInvoker] invoke failed, response output is null!");
				return result;
			}
			result = EntityUtils.toString(entity, "utf-8");
			return result;
		} catch (Exception e) {
			log.error("[HttpclientApiInvoker] invoke throw exception, details: {}", e);
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

	private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
		SSLConnectionSocketFactory sslsf = null;
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			}).build();
			sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {

				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					return true;
				}

				@Override
				public void verify(String host, SSLSocket ssl) throws IOException {
				}

				@Override
				public void verify(String host, X509Certificate cert) throws SSLException {
				}

				@Override
				public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
				}
			});
		} catch (GeneralSecurityException e) {
			log.error(e.getMessage(), e);
		}
		return sslsf;
	}

	public static void init() {
		// 设置连接池
		connMgr = new PoolingHttpClientConnectionManager();
		// 设置连接池大小
		connMgr.setMaxTotal(500);
		connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
		RequestConfig.Builder configBuilder = RequestConfig.custom();
		// 设置连接超时
		configBuilder.setConnectTimeout(60000);
		// 设置读取超时
		configBuilder.setSocketTimeout(60000);
		// 设置从连接池获取连接实例的超时
		configBuilder.setConnectionRequestTimeout(10000);
		// 在提交请求之前 测试连接是否可用
		configBuilder.setStaleConnectionCheckEnabled(true);
		requestConfig = configBuilder.build();
		log.info("[HttpclientApiInvoker] invoke init success and finish!!!");
	}

	/**
	 * 测试api
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		HttpclientApiInvoker.init();
		String s = HttpclientApiInvoker.reGetForward("https://api.huobi.pro/market/tickers", null);
		System.out.println(s);

	}
}
